package nl.utwente.ewi.hmi.multitouch.drivers.dtproxy;

import java.awt.Dimension;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import nl.utwente.ewi.hmi.multitouch.TouchDeviceInfo;
import nl.utwente.ewi.hmi.multitouch.io.TouchStream;
import nl.utwente.ewi.hmi.multitouch.io.TouchStreamProvider;

public class DTProxyStreamProvider implements TouchStreamProvider {

	private final List<DiamondTouchProxyDeviceInfo> touchDeviceInfos;

	private final Map<TouchDeviceInfo, TouchStream> registeredStreams;
	
	public DTProxyStreamProvider(InetAddress host, int port) throws IOException {
		List<DiamondTouchProxyDeviceInfo> touchDeviceInfos = new LinkedList<DiamondTouchProxyDeviceInfo>();

		final DatagramSocket socket;

		if(host.isMulticastAddress()) {
			MulticastSocket multicastSocket = new MulticastSocket(port);
			multicastSocket.joinGroup(host);
			socket = multicastSocket;
		} else {
			socket = new DatagramSocket(port, host);
		}

		byte[] backingBuffer = new byte[65536];

		ByteBuffer buffer = ByteBuffer.wrap(backingBuffer);

		DatagramPacket packet = new DatagramPacket(backingBuffer, backingBuffer.length);

		socket.receive(packet);
		
		buffer.rewind();
		
		DiamondTouchPacket dtPacket = DiamondTouchPacket.fromByteBuffer(buffer);

		DiamondTouchProxyDeviceInfo info = new DiamondTouchProxyDeviceInfo(new Dimension(dtPacket.columns, dtPacket.rows), dtPacket.frames.size(), host, port);
		
		touchDeviceInfos.add(info);
		
		socket.close();
		
		this.touchDeviceInfos = Collections.unmodifiableList(touchDeviceInfos);

		registeredStreams = new HashMap<TouchDeviceInfo, TouchStream>();

		for(DiamondTouchProxyDeviceInfo touchDeviceInfo : this.touchDeviceInfos) {
			registeredStreams.put(touchDeviceInfo, new DTProxyStream(touchDeviceInfo));
		}
	}

	@Override
	public List<? extends TouchDeviceInfo> getTouchDeviceInfoList() {
		return this.touchDeviceInfos;
	}

	@Override
	public TouchStream getTouchStream(TouchDeviceInfo deviceInfo) {
		return this.registeredStreams.get(deviceInfo);
	}

}
